﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace P
{


    //      一、什么是代理模式？
    //代理模式（Proxy Pattern）是一种结构型设计模式，它的作用是：
    //为某个对象提供一个“替身”或“代理”，由代理对象控制对原对象的访问。
    //代理对象在客户端和目标对象之间起到了中介作用，可以在调用真实对象之前或之后加入额外逻辑（如权限控制、延迟加载、缓存等）

    //      二、适用场景
    //代理模式常用于以下情况：

    //场景 示例
    //控制访问      用户权限校验、网络权限检查
    //延迟加载      大型图片/视频对象只在访问时加载
    //远程代理      客户端操作远程服务对象（RPC、WCF）
    //缓存代理      多次请求返回同一数据时，使用缓存提高性能
    //日志/审计代理   跟踪对象操作记录
    //安全代理      限制特定操作只能由授权对象执行

    //      三、结构组成（UML）
    //角色                                说明
    //Subject（抽象主题）     	定义真实对象和代理对象的公共接口
    //RealSubject（真实主题）	    实际执行业务逻辑的类
    //Proxy（代理）	            控制访问真实对象，可以添加额外逻辑
    // 

    //    五、代理模式的优缺点
    //✅ 优点
    //控制访问：可以限制谁访问目标对象。
    //增强功能：如缓存、延迟加载、日志记录等。
    //解耦真实对象与客户端。实现真实对象跟客户端的松耦合


    //     六、代理模式分类（常见子类）
    //      类型                          说明
    //保护代理（权限控制）	    判断是否有权限调用目标对象
    //虚拟代理（延迟加载）	    控制资源的创建（如图像、文件等）
    //远程代理（RPC、Web服务）	访问在其他机器上的对象
    //缓存代理（结果复用）	    存储并复用已有结果，可以用来减少重复调用
    //智能代理（监控、计数、日志）	增加统计、记录等操作


    //    七、实际开发中的应用
    //应用领域                      代理用途
    //WPF开发         使用动态代理实现 INotifyPropertyChanged
    //AOP框架         使用代理动态注入日志、安全校验
    //EF Core         使用代理类实现延迟加载导航属性
    //Revit/CAD开发   包装图元元素，实现只读、防止误改
    //网络请求        对远程服务接口生成代理类进行调用（如 WCF、gRPC）


    //    九、总结一句话
    //当你希望“在访问某个对象之前或之后加入额外逻辑或控制”，但又不想修改该对象本身时，就使用代理模式。


    //我们以“网络图片延迟加载”为例说明。

    /// <summary>
    /// 1.抽象接口
    /// </summary>
    public interface IImage
    {
        void Display();
    }

    /// <summary>
    /// 真实对象
    /// </summary>
    public class RealImage : IImage
    {
        private string filename;

        public RealImage(string filename)
        {
            this.filename = filename;
            LoadFromDisk(); // 模拟耗时加载
        }

        private void LoadFromDisk()
        {
            Console.WriteLine($"第一次加载图片---: {filename}");
            Console.WriteLine($"加载花费了60s");
        }

        public void Display()
        {
            Console.WriteLine($"显示图像: {filename}");
        }
    }

    /// <summary>
    /// 代理对象
    /// </summary>
    public class ProxyImage : IImage
    {
        private string filename;
        private RealImage realImage;

        public ProxyImage(string filename)
        {
            this.filename = filename;
        }

        public void Display()
        {
            //在访问某个对象之前或之后加入额外代码逻辑或控制, 但又不想修改该对象本身时

            if (realImage == null)
            {
                //调用延迟加载
                realImage = new RealImage(filename); //构造函数中有延迟加载
            }
            realImage.Display();
        }
    }



    class Program
    {
        static void Main(string[] args)
        {
            //func1();
            func2();
            Console.ReadKey();
        }

        static void func1()
        {
            Client client = new Client();
            client.Run();
        }

        static void func2()
        {
            IImage image = new ProxyImage("cat.jpg");
            Console.WriteLine("图像已创建，但尚未加载。...");
            image.Display(); // 第1次加载
            image.Display(); // 第2次不再加载
            image.Display(); // 第3次不再加载
        }

    }
}
